#include "stdafx.h"
#include <JeayeSDK/double_link.h>

BOOL double_link::push_front(double_iterator *iter)
{
	_ASSERT(this != NULL && iter != NULL);

	iter->m_next = iter->m_prev = NULL;

	if (this->m_head == NULL) {
		this->m_tail = iter;
	}
	else {
		_ASSERT(this->m_tail != NULL);
		/**/
		iter->m_next = this->m_head;
		this->m_head->m_prev = iter;
	}

	this->m_head = iter;
	this->m_count++;

	return TRUE;
}

BOOL double_link::push_back(double_iterator *iter)
{
	_ASSERT(this != NULL && iter != NULL);

	iter->m_next = iter->m_prev = NULL;

	if (this->m_head == NULL) {
		this->m_head = iter;
	}
	else {
		_ASSERT(this->m_tail != NULL);
		/**/
		this->m_tail->m_next = iter;
		iter->m_prev = this->m_tail;
	}
	this->m_tail = iter;
	this->m_count++;

	return TRUE;
}

BOOL double_link::insert_before(double_iterator *before, double_iterator *insert)
{
	double_iterator *prev = NULL;
	_ASSERT( before != NULL && insert != NULL);
	if (before == NULL || insert == NULL)
		return FALSE;

	if (this->m_head == NULL || this->m_head == this->m_tail || this->m_head == before) {
		return this->push_front(insert);
	}

	prev = before->m_prev;
	prev->m_next = insert;

	insert->m_prev = prev;
	insert->m_next = before;

	before->m_prev = insert;

	this->m_count++;

	return TRUE;
}

BOOL double_link::insert_after(double_iterator *after, double_iterator *insert)
{
	double_iterator *next = NULL;
	_ASSERT(after != NULL && insert != NULL);
	if (this == NULL || after == NULL || insert == NULL)
		return FALSE;

	if (this->m_tail == NULL || this->m_head == this->m_tail || this->m_tail == after) {
		return this->push_back( insert);
	}

	next = after->m_next;

	insert->m_prev = after;
	insert->m_next = next;

	after->m_next = insert;

	this->m_count++;

	return TRUE;
}

BOOL double_link::append(double_link *append)
{
	if (this == NULL || append == NULL || append->empty() == TRUE)
		return FALSE;

	if (this->empty() == TRUE) {
		this->m_head = append->m_head;
		this->m_tail = append->m_tail;
		this->m_count = append->m_count;

		return TRUE;
	}

	this->m_tail->m_next = append->m_head;
	append->m_head->m_prev = this->m_tail;

	this->m_tail = append->m_tail;
	this->m_count += append->m_count;

	return TRUE;
}

BOOL double_link::swap(double_link *rem, double_iterator *iter)
{
	_ASSERT(this != NULL && rem != NULL && iter != NULL);
	if (this == NULL || rem == NULL || iter == NULL)
		return FALSE;

	if (rem->remove(iter) == NULL) {
		_ASSERT(FALSE);
		return FALSE;
	}

	return this->push_back( iter);
}

BOOL double_link::push_sort(double_iterator *insert, BOOL(*fn_sort)(double_iterator*, double_iterator*))
{
	_ASSERT(this != NULL && insert != NULL && fn_sort != NULL);
	if (this == NULL || insert == NULL || fn_sort == NULL)
		return FALSE;

	if (this->m_head != NULL) {
		double_link_for_each_next(val, this, {
			if (fn_sort(insert, val)) {
				return this->insert_before(val, insert);
			}
		});
	}

	return this->push_back( insert);
}

double_iterator* double_link::remove_head()
{
	double_iterator *ret = m_head;

	m_head = ret->m_next;
	if (m_head != NULL) {
		/*clean*/
		m_head->m_prev = NULL;
		m_count--;
		_ASSERT(m_count >= 0);
	}
	else if (m_tail == ret) {
		/* link is empty clear link */
		m_head = m_tail = NULL;
		m_count = 0;
	}
	else {
		_ASSERT(FALSE);
	}

	/**/
	ret->m_next = ret->m_prev = NULL;
	return ret;
}

double_iterator* double_link::remove_tail()
{
	double_iterator *ret = this->m_tail;

	this->m_tail = ret->m_prev;
	if (this->m_tail) {
		/*clean*/
		this->m_tail->m_next = NULL;
		this->m_count--;
		_ASSERT(this->m_count >= 0);
	}
	else if (this->m_head == ret) {
		/* link is empty clear link */
		this->m_head = this->m_tail = NULL;
		this->m_count = 0;
	}
	else {
		_ASSERT(FALSE);
	}

	/**/
	ret->m_next = ret->m_prev = NULL;
	return ret;
}

double_iterator* double_link::remove(double_iterator *iter)
{
	_ASSERT(this != NULL && iter != NULL);
	if (this->empty() == TRUE || (iter == NULL))
		return NULL;

	/*remove head*/
	if (iter == this->m_head) {
		return this->remove_head();
	}
	else if (iter == this->m_tail) {
		/*remove tail*/
		return this->remove_tail();
	}

	_ASSERT(iter->m_prev != NULL && iter->m_next != NULL);
	if (iter->m_prev == NULL || iter->m_next == NULL) {
		_ASSERT(FALSE);
		return NULL;
	}

	iter->m_prev->m_next = iter->m_next;
	iter->m_next->m_prev = iter->m_prev;

	this->m_count--;
	_ASSERT(this->m_count >= 0);
	/**/
	iter->m_next = iter->m_prev = NULL;

	return iter;
}
